package com.tanovo.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.tanovo.bo.*;
import com.tanovo.config.UserInfoContext;
import com.tanovo.domain.*;
import com.tanovo.exception.ServiceException;
import com.tanovo.mapper.ClientMapUserMapper;
import com.tanovo.mapper.UserBaseInfoMapper;
import com.tanovo.mapper.UserMapper;
import com.tanovo.mapper.UserRorleMapper;
import com.tanovo.service.ICompanyService;
import com.tanovo.service.IOauthClientDetailsService;
import com.tanovo.service.ISmsService;
import com.tanovo.service.IUserService;
import com.tanovo.util.ByteUtil;
import com.tanovo.util.ExcelImportUtil;
import com.tanovo.util.ValidateCodeUtil;
import com.tanovo.util.sm3.SM3;
import com.tanovo.util.sm4.SM4Utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserRorleMapper userRorleMapper;
    @Autowired
    private UserBaseInfoMapper userBaseInfoMapper;
    @Autowired
    private ClientMapUserMapper clientMapUserMapper;
    @Autowired
    private ICompanyService iCompanyService;
    @Autowired
    private ISmsService iSmsService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private IOauthClientDetailsService iOauthClientDetailsService;

    private final String registerCode = "user:register:code";
    private final String imageCode = "user:image:code";

    @Override
    public User getUserbyTokenReqest(TokenRequest tokenRequest) {

        UserExample example = new UserExample();
        if (!StringUtils.isEmpty(tokenRequest.getPhone())) {
            example.createCriteria().andPhoneEqualTo(tokenRequest.getPhone().trim());
        }
        if (!StringUtils.isEmpty(tokenRequest.getEmail())) {
            example.createCriteria().andPhoneEqualTo(tokenRequest.getEmail().trim());
        }
        if (!StringUtils.isEmpty(tokenRequest.getLoginName())) {
            example.createCriteria().andPhoneEqualTo(tokenRequest.getLoginName().trim());
        }
        List<User> userList = userMapper.selectByExample(example);
        if (!CollectionUtils.isEmpty(userList)) {
            User user = userList.get(0);
            SecretBo secretBo = this.generateSecretPassword(tokenRequest.getPassword(), user.getSalt());
            if (secretBo.getSecretPassword().equals(user.getPassword())) {
                return userList.get(0);
            }
        }
        return null;
    }

    @Override
    public void addPasswdUser(User user) {
        String salt = UUID.randomUUID().toString().replace("-", "");
        SecretBo secretBo = this.generateSecretPassword(user.getPassword(), salt);
        user.setPassword(secretBo.getSecretPassword());
        user.setSalt(salt);
        user.setDelFlag(0);
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        this.add(user);
    }

    @Override
    public void add(User user) {
        user.setDelFlag(0);
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        userMapper.insertSelective(user);
    }

    @Override
    public void addUserBaseInfo(UserBaseInfo userBaseInfo) {
        userBaseInfo.setDelFlag(0);
        userBaseInfo.setCreateTime(new Date());
        userBaseInfo.setUpdateTime(new Date());
        userBaseInfoMapper.insertSelective(userBaseInfo);
    }

    /**
     * 用户原始密码生成新的加密密码
     *
     * @param originPassword
     * @return
     */
    public SecretBo generateSecretPassword(String originPassword, String salt) {
        String passwordHex = ByteUtil.byteToHex(originPassword.getBytes());
        SM4Utils sm4 = new SM4Utils();
        String sm4Password = sm4.encryptData_ECB(passwordHex, salt);
        String sm3HASHPassword = SM3.generateSM3HASH(sm4Password);
        SecretBo secretBo = new SecretBo();
        secretBo.setSecretPassword(sm3HASHPassword);
        return secretBo;
    }

    @Override
    public User getUserById(String userId) {
        User user = userMapper.selectByPrimaryKey(new Integer(userId));
        if (user != null && user.getDelFlag() == 0) {
            return user;
        }
        return null;
    }


    @Override
    public void deleteByIdList(List<Integer> userIdList) {
        if (CollectionUtils.isEmpty(userIdList)) {
            return;
        }
        String clientId = UserInfoContext.getUser().getClientId();
        if (StringUtils.isEmpty(clientId)) {
            return;
        }
        userMapper.deleteByIdList(clientId, userIdList);
    }

    @Override
    public List<UserBaseInfo> listUser(UserFindBo userFindBo) {
        String clientId = UserInfoContext.getUser().getClientId();
        userFindBo.setClientId(clientId);
        userFindBo.setCompanyId(UserInfoContext.getUser().getCompanyId().toString());
        List<UserBaseInfo> userList = userMapper.getUserList(userFindBo);
        return userList;
    }

    @Override
    public UserBaseInfo getUserDetail(Integer userId) {
        UserBaseInfoExample example = new UserBaseInfoExample();
        example.createCriteria().andUserIdEqualTo(userId)
                .andDelFlagEqualTo(0);
        List<UserBaseInfo> userList = userBaseInfoMapper.selectByExample(example);
        if (!CollectionUtils.isEmpty(userList)) {
            return userList.get(0);
        }
        return null;
    }

    @Override
    public void updateUser(User user) {
        user.setUpdateTime(new Date());
        user.setUpdateBy(UserInfoContext.getUser().getId() + "");
        user.setPassword(null);//不可以编辑密码
        user.setSalt(null);
        userMapper.updateByPrimaryKeySelective(user);
    }

    @Override
    @Transactional
    public void bindRole(UserRoleBindBo userRoleBindBo) {
        Date date = new Date();
        List<Integer> roleIdBindList = userRoleBindBo.getRoleIdBindList();
        if (!CollectionUtils.isEmpty(roleIdBindList)) {
            UserCore user = UserInfoContext.getUser();
            for (Integer roleId : roleIdBindList) {
                UserRole userRole = new UserRole();
                userRole.setDelFlag(0);
                userRole.setUserId(userRoleBindBo.getUserId());
                userRole.setRoleId(roleId);
                userRole.setCreateBy(user.getId() + "");
                userRole.setUpdateBy(user.getId() + "");
                userRole.setCreateTime(date);
                userRole.setClientId(UserInfoContext.getUser().getClientId());
                userRole.setUpdateTime(date);
                userRole.setCompanyId(UserInfoContext.getUser().getCompanyId());
                userRorleMapper.insert(userRole);
            }
        }
        this.deleteRole(userRoleBindBo);
    }

    @Override
    @Transactional
    public void deleteRole(UserRoleBindBo userRoleBindBo) {
        Date date = new Date();
        List<Integer> roleIdUnBindList = userRoleBindBo.getRoleIdUnBindList();
        if (!CollectionUtils.isEmpty(roleIdUnBindList)) {
            UserCore user = UserInfoContext.getUser();
            UserRoleExample example = new UserRoleExample();
            example.createCriteria().andRoleIdIn(roleIdUnBindList)
                    .andUserIdEqualTo(userRoleBindBo.getUserId())
                    .andClientIdEqualTo(UserInfoContext.getUser().getClientId())
                    .andDelFlagEqualTo(0)
                    .andCompanyIdEqualTo(UserInfoContext.getUser().getCompanyId());
            List<UserRole> userRoleList = userRorleMapper.selectByExample(example);
            for (UserRole userRole : userRoleList) {
                userRole.setDelFlag(1);
                userRole.setUpdateTime(date);
                userRole.setUpdateBy(user.getId().toString());
                userRorleMapper.updateByPrimaryKeySelective(userRole);
            }
        }
    }

    @Override
    public void restPassword(UserRestBo userRestBo) {
        User user = new User();
        UserCore userCore = UserInfoContext.getUser();
        user.setDelFlag(0);
        Date date = new Date();
        user.setUpdateTime(date);
        user.setUpdateBy(userCore.getId().toString());
        String salt = UUID.randomUUID().toString().replace("-", "");
        SecretBo secretBo = this.generateSecretPassword(userRestBo.getNewPassword(), salt);
        user.setPassword(secretBo.getSecretPassword());
        user.setSalt(salt);
        UserExample userExample = new UserExample();
        userExample.createCriteria().andPhoneEqualTo(userRestBo.getPhone());
        userMapper.updateByExample(user, userExample);
    }

    @Override
    @Transactional
    public void register(UserRegisterBo userRegisterBo) {
        User user = new User();
        user.setPhone(userRegisterBo.getPhone());
        user.setPassword(userRegisterBo.getPassword());
        String redisCode = stringRedisTemplate.opsForValue().get(registerCode + userRegisterBo.getPhone());
        if (!userRegisterBo.getCode().equals(redisCode)) {
            throw new ServiceException("验证码不存在或超时");
        }
        //判断电话是否在用户表中存在
        User dataUser = this.getUserByPhone(userRegisterBo.getPhone());
        if (dataUser != null) {
            throw new ServiceException("用户已经存在");
        }
        this.addPasswdUser(user);
        //绑定公司关系
        iCompanyService.bindUser(user, userRegisterBo.getCompanyId());
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setUserId(user.getId());
        userBaseInfo.setPhone(user.getPhone());
        userBaseInfo.setUpdateBy(user.getId().toString());
        userBaseInfo.setCreateBy(user.getId().toString());
        this.addUserBaseInfo(userBaseInfo);
    }

    @Override
    public User getUserByUnionid(String unionid) {
        UserExample userExample = new UserExample();
        userExample.createCriteria().andUnionidEqualTo(unionid).andDelFlagEqualTo(0);
        List<User> userList = userMapper.selectByExample(userExample);
        if (!CollectionUtils.isEmpty(userList)) {
            return userList.get(0);
        }
        return null;
    }

    @Override
    public List<UserBaseInfo> getCtfUserList(List<Integer> userIdList) {
        if (CollectionUtils.isEmpty(userIdList)) {
            return null;
        }
        UserBaseInfoExample example = new UserBaseInfoExample();
        example.createCriteria().andUserIdIn(userIdList);
        List<UserBaseInfo> userBaseInfoList = userBaseInfoMapper.selectByExample(example);
        return userBaseInfoList;
    }

    @Override
    @Transactional
    public void addUserInfo(UserBaseInfoBo userBaseInfoBo) {
        User dbUser = this.getUserByPhone(userBaseInfoBo.getPhone());
        if (dbUser != null) {
            throw new ServiceException("用户已经存在");
        }
        User user = new User();
        BeanUtils.copyProperties(userBaseInfoBo, user);
        this.addPasswdUser(user);
        userBaseInfoBo.setUserId(user.getId());
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        BeanUtils.copyProperties(userBaseInfoBo, userBaseInfo);
        userBaseInfo.setDelFlag(0);
        userBaseInfo.setCreateTime(new Date());
        userBaseInfo.setUpdateTime(new Date());
        userBaseInfoMapper.insertSelective(userBaseInfo);
        //绑定个人用户公司和当前登录公司
        if (UserInfoContext.getUser().getCompanyId() == 0) {//个人用户公司
            iCompanyService.bindUser(user, UserInfoContext.getUser().getCompanyId());
        } else {
            iCompanyService.bindUser(user, 0);
            iCompanyService.bindUser(user, UserInfoContext.getUser().getCompanyId());
        }

        //绑定关系到 所属平台
        ClientMapUser clientMapUser = new ClientMapUser();
        clientMapUser.setClientId(UserInfoContext.getUser().getClientId());
        clientMapUser.setUserId(userBaseInfo.getUserId().toString());
        clientMapUser.setCompanyId(UserInfoContext.getUser().getCompanyId());
        clientMapUser.setDelFlag(0);
        clientMapUser.setCreateTime(new Date());
        clientMapUser.setUpdateTime(new Date());
        clientMapUser.setUpdateBy(userBaseInfoBo.getUpdateBy());
        clientMapUser.setCreateBy(userBaseInfoBo.getCreateBy());
        clientMapUserMapper.insertSelective(clientMapUser);
    }

    @Override
    @Transactional
    public void updateUserBaseInfo(UserBaseInfoBo userBaseInfoBo) {
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        BeanUtils.copyProperties(userBaseInfoBo, userBaseInfo);
        userBaseInfo.setUpdateTime(new Date());
        userBaseInfo.setUpdateBy(UserInfoContext.getUser().getId().toString());
        User user = new User();
        user.setId(userBaseInfo.getUserId());
        user.setPhone(userBaseInfo.getPhone());
        this.updateUser(user);
        userBaseInfoMapper.updateByPrimaryKeySelective(userBaseInfo);
    }

    @Override
    public User getUserByPhone(String phone) {
        UserExample userExample = new UserExample();
        userExample.createCriteria().andPhoneEqualTo(phone).andDelFlagEqualTo(0);
        List<User> userList = userMapper.selectByExample(userExample);
        if (CollectionUtils.isEmpty(userList)) {
            return null;
        }
        return userList.get(0);
    }


    @Override
    public void bindSuperAdminRole(Role superAdmin, Integer userId) {
        UserCore user = UserInfoContext.getUser();
        Date date = new Date();
        UserRole userRole = new UserRole();
        userRole.setDelFlag(0);
        userRole.setUserId(userId);
        userRole.setRoleId(superAdmin.getId());
        userRole.setCreateBy(user.getId() + "");
        userRole.setUpdateBy(user.getId() + "");
        userRole.setCreateTime(date);
        userRole.setClientId(superAdmin.getClientId());
        userRole.setUpdateTime(date);
        userRole.setCompanyId(superAdmin.getCompanyId());
        userRorleMapper.insert(userRole);
    }

    @Override
    public void bindSuperAdminToCompany(Company company) {
        User user = new User();
        user.setId(1);//id是超管
        user.setDelFlag(0);
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        user.setUpdateBy(company.getUpdateBy());
        user.setCreateBy(company.getCreateBy());
        iCompanyService.bindUser(user, company.getId());
    }


    @Override
    public List<UserBaseInfoBo> userApproveList(UserCore user) {
        List<UserBaseInfoBo> bolist = userBaseInfoMapper.userApproveList(user);
        return bolist;
    }

    @Override
    public void openUserClient(UserClientApproveBo userClientApprove) {
        ClientMapUserExample example = new ClientMapUserExample();
        example.createCriteria().andCompanyIdEqualTo(userClientApprove.getCompanyId())
                .andClientIdEqualTo(userClientApprove.getClientId())
                .andUserIdEqualTo(userClientApprove.getUserId().toString());
        ClientMapUser clientMapUser = new ClientMapUser();
        clientMapUser.setEnable(userClientApprove.getStatus());
        clientMapUser.setUpdateTime(new Date());
        clientMapUserMapper.updateByExampleSelective(clientMapUser, example);
    }

    @Override
    public List<UserBaseInfo> listPersonalUser(UserFindBo userFindBo) {
        List<UserBaseInfo> userList = userMapper.listPersonalUser(userFindBo);
        return userList;
    }

    @Override
    public void bindApp(UserBindAppBo userBindAppBo) {
        //判断用是否绑定了公司 没有绑定 就绑定公司
        List<CompanyMapUser> companyMapUserList = iCompanyService.getCompanyMapUserList(userBindAppBo.getUserId());
        boolean bindCompanyFlag = true;
        if (CollectionUtils.isEmpty(companyMapUserList)) {
            bindCompanyFlag = true;

        } else {
            for (CompanyMapUser cmu : companyMapUserList) {
                if (cmu.getCompanyId().equals(userBindAppBo.getCompanyId())) {
                    bindCompanyFlag = false;
                    break;
                }
            }
        }
        if (bindCompanyFlag) {
            User user = new User();
            user.setId(userBindAppBo.getUserId());
            iCompanyService.bindUser(user, userBindAppBo.getCompanyId());
        }
        ClientMapUser clientMapUser = new ClientMapUser();
        clientMapUser.setUserId(userBindAppBo.getUserId().toString());
        clientMapUser.setCompanyId(userBindAppBo.getCompanyId());
        clientMapUser.setClientId(userBindAppBo.getClientId());
        clientMapUser.setEnable(1);
        clientMapUser.setUpdateTime(new Date());
        clientMapUserMapper.insertSelective(clientMapUser);
    }

    @Override
    public void bindRole(UserRole userRole) {
        userRole.setDelFlag(0);
        userRole.setCreateTime(new Date());
        userRole.setUpdateTime(new Date());
        userRorleMapper.insert(userRole);
    }

    @Override
    public void sendRegisterCode(String phone, String imageCode) {
        if(StringUtils.isEmpty(imageCode)){
            throw new ServiceException("图片验证码不能为空");
        }
        String redisImageCode = stringRedisTemplate.opsForValue().get(imageCode + phone);
        if(imageCode.equals(redisImageCode)){
            Long code = Math.round((Math.random() + 1) * 1000);
            iSmsService.send(phone, code);
            log.info("{}，用户的短信验证码,{}", phone, code);
            stringRedisTemplate.opsForValue().set(registerCode + phone, code.toString(), 10, TimeUnit.MINUTES);
        }else {
            throw new ServiceException("图片验证码不正确");
        }

    }


    @Override
    @Transactional
    public InnerRegisterResp userInnerRegister(UserInsertBo userInsertBo) {
        //判断电话是否在用户表中存在
        InnerRegisterResp registerResp = new InnerRegisterResp();
        User dataUser = this.getUserByPhone(userInsertBo.getPhone());
        if (dataUser != null) {
            registerResp.setCode(202);
            registerResp.setMessage("用户手机号已存在");
            return registerResp;
        }
        User user = new User();
        BeanUtils.copyProperties(userInsertBo, user);
        this.addPasswdUser(user);
        //绑定应用
        UserBindAppBo bindAppBo = new UserBindAppBo();
        bindAppBo.setClientId(userInsertBo.getClientId());
        bindAppBo.setCompanyId(userInsertBo.getCompanyId());
        bindAppBo.setUserId(user.getId());
        this.bindApp(bindAppBo);
        if (userInsertBo.getCompanyId() != 0) {
            iCompanyService.bindUser(user, 0);
        }
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setUserId(user.getId());
        userBaseInfo.setPhone(user.getPhone());
        userBaseInfo.setUsername(userInsertBo.getUsername());
        userBaseInfo.setAge(userInsertBo.getAge());
        userBaseInfo.setIdCard(userInsertBo.getIdCard());
        userBaseInfo.setUpdateBy(user.getId().toString());
        userBaseInfo.setCreateBy(user.getId().toString());
        this.addUserBaseInfo(userBaseInfo);
        registerResp.setCode(0);
        registerResp.setMessage("注册成功");
        registerResp.setData(userBaseInfo);
        return registerResp;
    }

    @Override
    @Transactional
    public void importExcelUser(MultipartFile file, UserCore userCore) {
        try {
            List<UserBaseInfoExcelBo> list = new ExcelImportUtil(UserBaseInfoExcelBo.class).readExcel(file.getInputStream(), 1, 0);
            log.info(JSONObject.toJSONString(list));
            for (UserBaseInfoExcelBo bo : list) {
                //首先判断用户是否在系统中 如果不在系统中添加到系统中
                User user = this.getUserByPhone(bo.getPhone());
                if (user == null) {
                    user = new User();
                    BeanUtils.copyProperties(bo, user);
                    if(StringUtils.isEmpty(user.getPassword())){
                        user.setPassword("123456");
                    }
                    this.addPasswdUser(user);
                    bo.setUserId(user.getId());
                    UserBaseInfo userBaseInfo = new UserBaseInfo();
                    BeanUtils.copyProperties(bo, userBaseInfo);
                    userBaseInfo.setDelFlag(0);
                    userBaseInfo.setCreateTime(new Date());
                    userBaseInfo.setUpdateTime(new Date());
                    userBaseInfoMapper.insertSelective(userBaseInfo);
                }
                //判断用户是否绑定公司和应用
                boolean addCompanyFlag = false;
                List<CompanyMapUser> companyMapUserList = iCompanyService.getCompanyMapUserList(user.getId());
                if(!CollectionUtils.isEmpty(companyMapUserList)){
                    for (CompanyMapUser cu : companyMapUserList) {
                        if (cu.getCompanyId().equals(userCore.getCompanyId())) {
                            addCompanyFlag = true;
                            break;
                        }
                    }
                }
                if(!addCompanyFlag){
                    iCompanyService.bindUser(user,userCore.getCompanyId());
                }
                List<ClientMapUser> userClientList= iOauthClientDetailsService.getUserClientList(user.getId(),userCore.getCompanyId(),userCore.getClientId());
                if(CollectionUtils.isEmpty(userClientList)){
                    OauthClientDetailsBo clientDetailsBo=new OauthClientDetailsBo();
                    clientDetailsBo.setUserId(user.getId());
                    clientDetailsBo.setCompanyId(userCore.getCompanyId());
                    clientDetailsBo.setClientId(userCore.getClientId());
                    clientDetailsBo.setCreateBy(userCore.getId().toString());
                    clientDetailsBo.setUpdateBy(userCore.getId().toString());
                    iOauthClientDetailsService.bindUserToClient(clientDetailsBo);
                }
            }
        } catch (IOException e) {
            log.error("excel导入出错",e);
            e.printStackTrace();
        }
    }

    @Override
    public ValidateCodeUtil.Validate getImageCodeByPhone(String phone) {
        ValidateCodeUtil.Validate randomCode = ValidateCodeUtil.getRandomCode();
        log.info("{}，用户的图片验证码,{}", phone, randomCode.getValue());
        stringRedisTemplate.opsForValue().set(imageCode + phone, randomCode.getValue(), 10, TimeUnit.MINUTES);
        return randomCode;
    }
}
